﻿using System;
using System.Data.Linq;
using System.Data.Common;
using System.Data.SqlClient;

using Fuse8.DomainFramework.Domain;
using Fuse8.DomainFramework.Common;

namespace Fuse8.DomainFramework.DataAccess.LinqDatabase
{
    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class DefaultHttpContextLinqUnitOfWorkFactory<T> : HttpContextLinqUnitOfWorkFactory<T>
        where T : class, IEntityObject, new()
    {
        #region Fields

        private string _connectionString;
        private Func<SqlConnection, DataContext> _creator;

        #endregion

        #region Constructor

        /// <summary>
        /// 
        /// </summary>
        /// <param name="creator"></param>
        /// <param name="connectionString"></param>
        public DefaultHttpContextLinqUnitOfWorkFactory(Func<SqlConnection, DataContext> creator, string connectionString)
        {
            _creator = creator;
            _connectionString = connectionString;
        }

        #endregion

        #region Override methods

        /// <summary>
        /// 
        /// </summary>
        /// <param name="withTransaction"></param>
        /// <returns></returns>
        public override IUnitOfWork<T> Create(bool withTransaction)
        {
            var connection = SqlConnectionFactoryWrapper.GetOrCreateConnection(CurrentHttpContext, _connectionString, withTransaction);
            
            var context = _creator(connection);

            if (withTransaction)
            {
                var transaction = context.Connection.BeginTransaction();

                context.Transaction = transaction;
            }

            return new LinqUnitOfWork<T>
            {
                CurrentContext = context
            };
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TMain"></typeparam>
        /// <param name="unitOfWork"></param>
        /// <returns></returns>
        public override IUnitOfWork<T> CreateFrom<TMain>(IUnitOfWork<TMain> unitOfWork)
        {
            Guard.ArgumentNotNull(unitOfWork, "unitOfWork");
            
            var dbUnitOfWork = unitOfWork as IDbUnitOfWork;
            if (dbUnitOfWork == null)
            {
                throw new NotSupportedException("Unit of work doesn't support db connections");
            }

            if (dbUnitOfWork.Transaction == null)
            {
                throw new NotSupportedException("Db transaction is required");
            }

            var context = _creator(dbUnitOfWork.Connection);

            context.Transaction = dbUnitOfWork.Transaction;

            return new LinqUnitOfWork<T>
            {
                CurrentContext = context
            };
        }

        /// <summary>
        /// 
        /// </summary>
        public override void CommitTransaction()
        {
            var linqUnitOfWork = Get(true) as LinqUnitOfWork<T>;

            if (linqUnitOfWork != null)
            {
                var transaction = linqUnitOfWork.CurrentContext.Transaction;

                if (transaction != null)
                {
                    transaction.Commit();
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public override void RollbackTransaction()
        {
            var linqUnitOfWork = Get(true) as LinqUnitOfWork<T>;

            if (linqUnitOfWork != null)
            {
                var transaction = linqUnitOfWork.CurrentContext.Transaction;

                if (transaction != null)
                {
                    transaction.Rollback();
                }
            }
        }

        #endregion
    }
}
